// Java VM for small microcontrollers
//
// (c) 2012, Digital Six Laboratories LLC
// All Rights Reserved
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
// and associated documentation files (the "Software"), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial 
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Original work based on NanoVM (http://www.harbaum.org/till/nanovm/index.shtml) for AVR microcontroller
//=========================================================================================================
// 
// stack.c
//
// Stack management
//
// A single stack is supported in this version meaning that threading is not supported.

//#include "config.h"
#include "vmerror.h"

#include "vm.h"
#include "vmheap.h"
#include "vmstack.h"

static tVmStack xdata *stack;     // the pysical base of the whole stack (incl. statics)
static tVmStack xdata *sp;        // the current stack pointer
static tVmStack xdata *stackbase; // the base of the runtime stack (excl. statics)

// *******************************************************************************************************************
// Public API

// void StackInitialize(U8 staticFields)
//
// Arguments:
//	U8 staticFields - Count of static fields
//
// Returns:
//  void - Nothing
void StackInitialize(U8 staticFields) 
{
	// the stack is generated by stealing from the heap. This
	// is possible since the class file tells us how many stack
	// elements the call to a method requires
	stack = (tVmStack xdata*)GetHeapBase();
	sp = stack-1;

	// steal one item for mains args and the space required for 
	// the static fields
	HeapSteal((1+staticFields)*sizeof(tVmStack)); 

	// increase stack pointer behind static fields
	sp += staticFields;
}

// void StackPush(tVmStack val)
//
// Arguments:
//	tVmStack val - value to push
//
// Returns:
//  void - Nothing
void StackPush(tVmStack val) 
{
	sp++;
	*sp=val;
	
//  	*(++sp) = val;
}

// tVmStack StackPop(void)
//
// Arguments:
//  nothing
//
// Returns:
//  tVmStack - value from stack
tVmStack StackPop(void) 
{
  	return *(sp--);
}
// int StackPopInt(void)
//
// Arguments:
//  nothing
//
// Returns:
//  tVmInt - value from stack
tVmInt StackPopInt(void) 
{
  	return VmStackToInt(*(sp--));
}

// tVmStack StackPeep(U8 index)
//
// Arguments:
//  U8 index- index into the stack
//
// Returns:
//  tVmStack - value from stack
tVmStack StackPeek(U8 index) 
{
  	return sp[-index];
}

// tVmInt StackPeep(U8 index)
//
// Arguments:
//  U8 index- index into the stack
//
// Returns:
//  tVmInt - value from stack
tVmInt StackPeekInt(U8 index) 
{
  	return VmStackToInt(sp[-index]);
}

// void *StackPopAddr(void)
//
// Arguments:
//  nothing
//
// Returns:
//  void * - address from the stack
void xdata *StackPopAddr(void) 
{
  	return VmGetAddress(*(sp--));
}

// void *StackPeekAddr(U8 index)
//
// Arguments:
//  U8 index- index into the stack
//
// Returns:
//  void * - address from the stack
void xdata *StackPeekAddr(U8 index) 
{
  	return VmGetAddress(sp[-index]);
}

# ifdef VM_INCLUDE_FLOAT
// tVmFloat StackPopFloat(void)
//
// Arguments:
//  nothing
//
// Returns:
//  tVmFloat - floating point value from the stack
tVmFloat StackPopFloat(void)
{
  	return VmStackToFloat(*(sp--));
}
// tVmFloat StackPeekFloat(U8 index)
//
// Arguments:
//  U8 index- index into the stack
//
// Returns:
//  tVmFloat - floating point value from the stack
tVmFloat StackPeekFloat(U8 index)
{
  	return VmStackToFloat(sp[-index]);
}
#endif

// void *StackAddToSp(S8 offset)
//
// Arguments:
//  S8 offset - offset to add to stack pointer
//
// Returns:
//  void nothing
void StackAddToSp(S8 offset) 
{
  	sp += offset;
}
// tVmStack xdata * GetStackPointer(void) 
//
// Arguments:
//  none
//
// Returns:
//  tVmStack - stack pointer
tVmStack xdata * GetStackPointer(void) 
{
  	return sp;
}

// tVmStack StackGetStaticVariable(U16 index)
//
// Arguments:
//  U16 index - index into stack
//
// Returns:
//  tVmStack - stack value at stack[index]
tVmStack StackGetStaticVariable(U16 index) 
{
  	return stack[index];
}
// void StackSetStaticVariable(U16 index, tVmStack value) 
//
// Arguments:
//  U16 index - index into stack
//  tVmStack value - value to put at stack[index]
//
// Returns:
//  tVmStack - stack pointer to location of stack[index]
void StackSetStaticVariable(U16 index, tVmStack value) 
{
  	stack[index] = value;
}
// void StackSaveBase(void)  
//
// Arguments:
// Returns:
//  none
void StackSaveBase(void) 
{
  	stackbase = GetStackPointer();
}

// BOOL StackIsEmpty(void)
// 
// Check if stack is empty
//
// Arguments:
//  None
// Returns:
//  BOOL - true if stack is empty
BOOL StackIsEmpty(void) 
{
  	return(sp == stackbase);
}
// BOOL StackHeapIdIsInUse(tHeapId)
// 
// Check if heapid is in use
//
// Arguments:
//  tHeapId id - heapid to check
// Returns:
//  BOOL - true if stack is empty
BOOL StackIsHeapIdInUse(tHeapId id) 
{
  	// we are searching for heap objects only
  	U16 i;
  	tVmReference id16 = id | VM_TYPE_HEAP;

  	// since the locals are physically part of the stack we only need
  	// to search the stack
  	for(i=0;i<sp-stack+1;i++) 
  	{
  		if(stack[i] == id16) return TRUE;
  	}

  	return FALSE;
}
